package com.ymatou.iapi.trading.userquery.testcase;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ymatou.iapi.optrade.parameter.enums.HunterOrderTypeEnum;
import com.ymatou.iapi.optrade.parameter.enums.LogisticsTypeEnum;
import com.ymatou.iapi.optrade.resp.TradingServiceResp;
import com.ymatou.iapi.synctrade.parameter.mongo.UserIndex;
import com.ymatou.iapi.synctrade.service.TradingSyncService;
import com.ymatou.iapi.trading.userquery.parameter.resp.OrderSummaryInfo;
import com.ymatou.iapi.trading.userquery.service.GetBuyerOrderListCountCall;
import com.ymatou.query.trading.api.parameter.GetBuyerOrderListCountBean;
import com.ymatou.query.trading.api.parameter.GetBuyerOrderListCountResponse;
import com.ymt.core.tool.Logger;
import com.ymt.utils.annotation.TestCase;
import com.ymt.utils.annotation.TestSuite;
import com.ymt.utils.tag.P1;
import com.ymt.utils.tag.P3;
import com.ymttest.business.service.OrderCallService;
import com.ymttest.business.service.YMTTrading.TradingCallService;
import com.ymttest.business.service.YMTTrading.TradingPlaceOrderCallService;
import com.ymttest.common.order.userquery.util.OrderHelper;
import com.ymttest.database.mongo.UserIndexQueryWapper;
import com.ymttest.database.mongo.config.UserIndexField;
import com.ymttest.utils.DataUtil;
import com.ymttest.utils.EnvSetup;
import com.ymttest.utils.constant.ECode;

/**
 * 获取用户订单数量 FreeMaker Template自动生成代码
 */
@TestSuite
public class Ts_GetBuyerOrderListCount {
	
	private static GetBuyerOrderListCountBean gbolcbean;
	private static GetBuyerOrderListCountCall gbolccall;

	private static GetBuyerOrderListCountResponse response;
	
	private static Integer userId = 20238699;
	
	// 是否缓存在内存中
	private static boolean isCountAggrInMemory = true;
	
	// 是否关闭统计
	private static boolean isDisableCount = false;
	
	@BeforeClass
	public static void setUp() {
		Logger.createResultFile("获取用户订单数量");
	}

	@Before
	public void caseUp() {
		gbolcbean = new GetBuyerOrderListCountBean();
		gbolccall = new GetBuyerOrderListCountCall();
		response = new GetBuyerOrderListCountResponse();
	}

	@AfterClass
	public static void tearDown() {
		Logger.generateResult(gbolccall.getOpurl());
	}

	@After
	public void caseDown() {
		Logger.end();
	}

	@SuppressWarnings("unchecked")
	private void verifyResult() throws JSONException {
		
		response = ConstructExpectedData();
		
		DataUtil.verifyEquals(response.AllComplaintedCount == 0 ? 0
				: response.AllComplaintedCount, gbolccall
				.getAllComplaintedCount(), "验证AllComplaintedCount");
		DataUtil.verifyEquals(response.ToBeEvaluatedOrderCount,
				gbolccall.getToBeEvaluatedOrderCount(),
				"验证ToBeEvaluatedOrderCount");
		
		JSONObject AllRecordCountDic = gbolccall.getAllRecordCountDic();
		
		DataUtil.verifyEquals(response.AllRecordCountDic.size(),
				AllRecordCountDic.length(), "验证AllRecordCountDic的订单状态个数");
		
		Iterator<String> keys = AllRecordCountDic.keys();
		
		while (keys.hasNext()) {
			
			String status = keys.next();
			int count = AllRecordCountDic.getInt(status);
			
			DataUtil.verifyEquals(
					response.AllRecordCountDic.get(Integer.valueOf(status)),
					count, "验证状态为" + status + "的订单数量");
		}
	}

	private GetBuyerOrderListCountResponse ConstructExpectedData() {

		if (isDisableCount) {
            GetBuyerOrderListCountResponse resp = new GetBuyerOrderListCountResponse();
            
			resp.setAllRecordCountDic(Maps.newHashMap());
			resp.getAllRecordCountDic().put(0, 0);
			resp.getAllRecordCountDic().put(1, 0);
			resp.getAllRecordCountDic().put(2, 0);
			resp.getAllRecordCountDic().put(3, 0);
			resp.getAllRecordCountDic().put(4, 0);
			resp.getAllRecordCountDic().put(12, 0);
			resp.getAllRecordCountDic().put(13, 0);
			resp.getAllRecordCountDic().put(18, 0);
			resp.getAllRecordCountDic().put(17, 0);
			resp.getAllRecordCountDic().put(16, 0);
			resp.getAllRecordCountDic().put(101, 0);
            resp.setAllComplaintedCount(0L);
            
            return resp;
        }
		
		Map<Integer, Integer> map = Maps.newHashMap();

		if (!CollectionUtils.isEmpty(gbolcbean.getOrderStatusList())) {
			
			gbolcbean.getOrderStatusList().forEach(os -> map.put(os, 0));
			gbolcbean.getOrderStatusList().removeAll(Arrays.asList(16, 101, 4));
		}
			
		List<Criteria> criteriaList = Lists.newArrayList(
				Criteria.where(UserIndexField.USER_ID).is(
						gbolcbean.getBuyerId()),
				Criteria.where(UserIndexField.DELETED).is(false),
				Criteria.where(UserIndexField.ORDER_TYPE).in(OrderHelper.getNotMemberOrderTypes()));
		
		if (!CollectionUtils.isEmpty(gbolcbean.getOrderStatusList())) {
			criteriaList.add(Criteria.where(UserIndexField.STATUS).in(
					gbolcbean.getOrderStatusList()));
		}

		if (!(gbolcbean.isIncludeHunter() && gbolcbean.isIncludeC2c())) {

			if (gbolcbean.isIncludeC2c())
				criteriaList.add(new Criteria().norOperator(Criteria.where(
						UserIndexField.HUNTER_ID).gt(0)));

			if (gbolcbean.isIncludeHunter())
				criteriaList.add(new Criteria().norOperator(Criteria.where(
						UserIndexField.HUNTER_ORDER_TYPE).is(
						HunterOrderTypeEnum.HUNTER_ORDER.getCode())));
		}

		// 默认只统计半年的订单
		if (gbolcbean.getBeginTime() != null)
			criteriaList.add(Criteria.where(UserIndexField.ADD_TIME).gte(
					gbolcbean.getBeginTime()));
		else
			criteriaList.add(Criteria.where(UserIndexField.ADD_TIME).gte(
					new DateTime().minusMonths(6).toDate()));

		if (gbolcbean.getEndTime() != null)
			criteriaList.add(Criteria.where(UserIndexField.ADD_TIME).lte(
					gbolcbean.getEndTime()));

		Criteria criteria = new Criteria().andOperator(criteriaList
				.toArray(new Criteria[0]));
		
		if (isCountAggrInMemory) {
			
			// 查出符合条件的订单，在内存做count
			Query query = new Query(criteria);
			query.fields().include(UserIndexField.STATUS);
			query.limit(1000);
			
			List<UserIndex> userIndices = new UserIndexQueryWapper().find(query,
					gbolcbean.getBuyerId(), UserIndex.class);
			int totalCount = 0;
			
			if (!CollectionUtils.isEmpty(userIndices)) {
				for (UserIndex user : userIndices) {
					totalCount++;
					map.putIfAbsent(user.getTradingStatus(), 0);
					map.put(user.getTradingStatus(),
							1 + map.get(user.getTradingStatus()));
				}
			}
			
			map.put(0, totalCount);
			
			GetBuyerOrderListCountResponse resp = new GetBuyerOrderListCountResponse();
			resp.setAllRecordCountDic(map);
			
			return resp;
        }
		
		Aggregation aggregation = Aggregation.newAggregation(
				Aggregation.match(criteria),
				Aggregation.group(UserIndexField.STATUS).count()
						.as("orderCount"), Aggregation.project("orderCount")
						.and("orderStatus").previousOperation());
		List<OrderSummaryInfo> summaryInfoList = new UserIndexQueryWapper()
				.aggregate(gbolcbean.getBuyerId(), aggregation,
						OrderSummaryInfo.class);

		int totalCount = 0;

		if (!CollectionUtils.isEmpty(summaryInfoList)) {
			for (OrderSummaryInfo orderSummaryInfo : summaryInfoList) {

				totalCount += orderSummaryInfo.getOrderCount();
				map.put(orderSummaryInfo.getOrderStatus(),
						orderSummaryInfo.getOrderCount());
			}
		}

		map.put(0, totalCount);

		long evaluateOrderCount = 0;

		if (gbolcbean.getToBeEvaluatedDays() > 0) {

			Date searchDate = DateTime.now()
					.minusDays(gbolcbean.getToBeEvaluatedDays()).toDate();
			criteria = new Criteria().andOperator(
					Criteria.where(UserIndexField.USER_ID).is(
							gbolcbean.getBuyerId()),
					Criteria.where(UserIndexField.NEEDS_EVALUATE).is(true),
					Criteria.where(UserIndexField.RECEIVE_TIME).gt(searchDate),
					Criteria.where(UserIndexField.DELETED).is(false))
					.norOperator(Criteria.where(UserIndexField.HUNTER_ID).gt(0));

			evaluateOrderCount = new UserIndexQueryWapper().count(
					Query.query(criteria), gbolcbean.getBuyerId());
		}
		
		GetBuyerOrderListCountResponse resp = new GetBuyerOrderListCountResponse();
		
		resp.setAllRecordCountDic(map);
		resp.setToBeEvaluatedOrderCount(evaluateOrderCount);
		
		return resp;
	}

	@Test
	@Category(P1.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_001() {
		Logger.start(true, "获取用户订单数量查询成功");
		try {
			int UserId = Integer.valueOf(EnvSetup.getData("BuyUserId"));
			gbolcbean.setBuyerId(UserId);
			
			// 查询开始时间
			gbolcbean.setBeginTime(DateTime.now().minusDays(10).toDate());
			
			// 查询结束时间
			gbolcbean.setEndTime(DateTime.now().toDate());
			
			gbolcbean.setToBeEvaluatedDays(10);

			// 订单状态
			ArrayList<Integer> list = new ArrayList<Integer>();
			// list.add(4);
			gbolcbean.setOrderStatusList(list);
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();
			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");

			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}

	@Test
	@Category(P1.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_002() {
		Logger.start(true, "获取用户订单数量+待点评数量，查询成功");
		try {
			int UserId = Integer.valueOf(EnvSetup.getData("BuyUserId"));
			gbolcbean.setBuyerId(UserId);

			// 查询开始时间
			gbolcbean.setBeginTime(DateTime.now().minusDays(10).toDate());

			// 查询结束时间
			gbolcbean.setEndTime(DateTime.now().toDate());

			// 订单状态
			ArrayList<Integer> list = new ArrayList<Integer>();
			list.add(18);
			gbolcbean.setOrderStatusList(list);
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");
			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}

	@Test
	@Category(P1.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_003() {
		Logger.start(true, "获取用户闪购订单数量，查询成功");
		try {
			int BuyerId = Integer.valueOf(EnvSetup.getData("BuyUserId"));

			gbolcbean.setBuyerId(BuyerId);
			
			// 查询开始时间
			gbolcbean.setBeginTime(DateTime.now().minusDays(10).toDate());

			// 查询结束时间
			gbolcbean.setEndTime(DateTime.now().toDate());

			// 订单状态
			ArrayList<Integer> list = new ArrayList<Integer>();
			list.add(18);
			gbolcbean.setOrderStatusList(list);
			
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");
			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}

	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_004() {
		Logger.start(true, "获取用户闪购订单数量，查询成功");
		try {
			int BuyerId = Integer.valueOf(EnvSetup.getData("BuyUserId"));

			gbolcbean.setBuyerId(BuyerId);

			// 查询开始时间
			gbolcbean.setBeginTime(DateTime.now().minusDays(10).toDate());

			// 查询结束时间
			gbolcbean.setEndTime(DateTime.now().toDate());

			// 订单状态
			ArrayList<Integer> list = new ArrayList<Integer>();
			list.add(19);
			gbolcbean.setOrderStatusList(list);
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");
			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}

	@Test
	@Category(P3.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_005() {
		Logger.start(true, "app端用户查询，查询成功");
		try {
			int BuyerId = Integer.valueOf(EnvSetup.getData("BuyUserId"));
			gbolcbean.setBuyerId(BuyerId);
			int toBeEvaluatedDays = 8;
			gbolcbean.setToBeEvaluatedDays(toBeEvaluatedDays);
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");
			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}

	@Test
	@Category(P1.class)
	@TestCase
	public void Tc_GetBuyerOrderListCount_006() {
		Logger.start(true, "app端用户查询，查询成功, 删除的订单不计数量");
		try {
			Logger.comment("准备一个状态为4的订单");

			// 创建一个拼邮的订单
			TradingServiceResp placeOrderResp = TradingPlaceOrderCallService
					.placeOrderWithThreeProcutInTwoOrder(false,
							BigDecimal.ZERO, userId,
							LogisticsTypeEnum.OVERSEAS_DELIVERY);
			
			long orderId = placeOrderResp.getOrderList().get(0).getOrderId();
			long sellerId = placeOrderResp.getOrderList().get(0).getSellerId();
			long userId = placeOrderResp.getUserId();
			// 支付订单
			TradingCallService.payOrder(userId,
					placeOrderResp.getPayableAmount(),
					placeOrderResp.getTradingId());
			// 接单
			TradingCallService.sellerAcceptOrder(sellerId, orderId);
			TradingSyncService.getSyncResult(orderId);
			// 拼邮国际段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 1);
			TradingSyncService.getSyncResult(orderId);
			// 拼邮国内段发货
			TradingCallService.delivery(sellerId, orderId,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 3);
			Logger.comment("前置数据准备结束");

			TradingCallService.confirmReceive(userId, orderId);

			TradingSyncService.getSyncResult(orderId);
			Logger.comment("订单准备完成");

			gbolcbean.setBuyerId((int)userId);
			int toBeEvaluatedDays = 10;
			gbolcbean.setToBeEvaluatedDays(toBeEvaluatedDays);
			// 发送请求
			gbolccall.setData(gbolcbean);
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");

			Logger.comment("准备一个状态为4的订单, 并删除该订单");
			// 创建一个拼邮的订单
			TradingServiceResp placeOrderResp1 = TradingPlaceOrderCallService
					.placeOrderWithThreeProcutInTwoOrder(false,
							BigDecimal.ZERO, userId,
							LogisticsTypeEnum.OVERSEAS_DELIVERY);

			long orderId1 = placeOrderResp1.getOrderList().get(0).getOrderId();
			long sellerId1 = placeOrderResp1.getOrderList().get(0).getSellerId();
			long userId1 = placeOrderResp1.getUserId();
			// 支付订单
			TradingCallService.payOrder(userId1,
					placeOrderResp1.getPayableAmount(),
					placeOrderResp1.getTradingId());
			// 接单
			TradingCallService.sellerAcceptOrder(sellerId1, orderId1);
			TradingSyncService.getSyncResult(orderId1);
			// 拼邮国际段发货
			TradingCallService.delivery(sellerId1, orderId1,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 1);
			TradingSyncService.getSyncResult(orderId1);
			// 拼邮国内段发货
			TradingCallService.delivery(sellerId1, orderId1,
					LogisticsTypeEnum.OVERSEAS_DELIVERY, 3);
			Logger.comment("前置数据准备结束");

			TradingCallService.confirmReceive(userId1, orderId1);

			TradingSyncService.getSyncResult(orderId1);

			new OrderCallService().salesMarkOrderDeleted(orderId, userId, true);
			
			TradingSyncService.getSyncResult(orderId1);
			Logger.comment("订单准备完成");

			// 发送请求
			gbolccall.callService();

			Logger.verifyEquals(ECode.SUCCESS, gbolccall.getCode(), "验证Code");
			verifyResult();
		} catch (Exception e) {
			Logger.fail(e);
		}
	}
}